package com.scut.chenlujie.library.clink.impl;

import com.scut.chenlujie.library.clink.core.IoArgs;
import com.scut.chenlujie.library.clink.core.IoProvider;
import com.scut.chenlujie.library.clink.core.Receiver;
import com.scut.chenlujie.library.clink.core.Sender;
import com.scut.chenlujie.library.clink.utils.CloseUtils;

import java.io.IOException;
import java.nio.channels.SocketChannel;
import java.util.concurrent.atomic.AtomicBoolean;



public class SocketChannelAdapter implements Sender, Receiver {
    private final AtomicBoolean isClosed = new AtomicBoolean(false);
    private final SocketChannel channel;
    private final IoProvider ioProvider;
    private final onChannelStatusChangedListener listener;
    private IoArgs.IoArgsEventProcessor receivedIoEventProcessor;
    private IoArgs.IoArgsEventProcessor sendIoEventProcessor;
    private volatile long lastWriteTime = System.currentTimeMillis();
    private volatile long lastReadTime = System.currentTimeMillis();

    public SocketChannelAdapter(SocketChannel channel, IoProvider ioProvider, onChannelStatusChangedListener listener) throws IOException {
        this.channel = channel;
        this.ioProvider = ioProvider;
        this.listener = listener;

        channel.configureBlocking(false);
    }

    @Override
    public void setReceiveListener(IoArgs.IoArgsEventProcessor processor) {
        this.receivedIoEventProcessor = processor;
    }

    @Override
    public boolean postReceiveAsync() throws IOException {
        if(isClosed.get()){
            throw new IOException("Current channel is closed!");
        }
        //进行callback状态监测，判断是否处于自循环状态
        inputCallback.checkAttachNull();

        //已经接收完packet，可以继续下一次监听某个socketChannel了 （之前为了不重复监听关闭了）
        return ioProvider.registerInput(channel , inputCallback);
    }

    @Override
    public long getLastReadTime() {
        return lastReadTime;
    }

    @Override
    public void setSendListener(IoArgs.IoArgsEventProcessor processor) {
        this.sendIoEventProcessor = processor;
    }

    @Override
    public boolean postSendAsync() throws IOException {
        if(isClosed.get()){
            throw new IOException("Current channel is closed!");
        }
        //进行callback状态监测，判断是否处于自循环状态
        inputCallback.checkAttachNull();
        return ioProvider.registerOutput(channel , outputCallback);
    }

    @Override
    public long getLastWriteTime() {
        return lastWriteTime;
    }


//    @Override
//    public void setReceivedListener(IoArgs.IOEventListener listener) {
//        this.receivedIoEventListener = listener;
//    }
//
//    @Override
//    public boolean receiveAsync(IoArgs args) throws IOException {
//        if(isClosed.get()){
//            throw new IOException("Current channel is closed!");
//        }
//        receivedArgsTemp = args;
//        //已经接收完packet，可以继续下一次监听某个socketChannel了 （之前为了不重复监听关闭了）
//        return ioProvider.registerInput(channel , inputCallback);
//    }
//
//    @Override
//    public boolean sendAsync(IoArgs args, IoArgs.IOEventListener listener) throws IOException {
//        if(isClosed.get()){
//            throw new IOException("Current channel is closed!");
//        }
//        sendIoEventListener = listener;
//        //当前发送的数据附加到回调中
//        outputCallback.setAttach(args);
//        return ioProvider.registerOutput(channel , outputCallback);
//
//    }

    @Override
    public void close() throws IOException {
        if(isClosed.compareAndSet(false ,true)){
            //解除注册回调
            ioProvider.unregisterInput(channel);
            ioProvider.unregisterOutput(channel);
            //关闭
            CloseUtils.close(channel);
            //回调当前channel已关闭
            listener.onChannelClosed(channel);
        }
    }

    private final IoProvider.HandleProviderCallback inputCallback = new IoProvider.HandleProviderCallback() {

        @Override
        protected void onProviderIo(IoArgs args) {
            if(isClosed.get()){
                return;
            }

            lastReadTime = System.currentTimeMillis();
            IoArgs.IoArgsEventProcessor processor = receivedIoEventProcessor;
            if (args == null) {
                args = processor.provideIoArgs();
            }

            try {
                if (args == null) {
                    processor.onConsumeFailed(null, new IOException("ProvideIoArgs is null."));
                } else {
                    //从channel中读取的数量
                    int count = args.readFrom(channel);
                    if (count == 0) {
                        System.out.println("Current read zero data!");
                    }
                    if (args.remained()) {
                        attach = args;
                        ioProvider.registerInput(channel, this);
                    } else {
                        attach = null;
                        processor.onConsumeCompleted(args);
                    }
                }
            }catch (IOException ignored){
                CloseUtils.close(SocketChannelAdapter.this);
            }
        }
    };

    //这些callback都是runnable
    private final IoProvider.HandleProviderCallback outputCallback = new IoProvider.HandleProviderCallback() {

        @Override
        protected void onProviderIo(IoArgs args) {
            if(isClosed.get()){
                return;
            }
            lastWriteTime = System.currentTimeMillis();
            IoArgs.IoArgsEventProcessor processor = sendIoEventProcessor;
            if (args == null) {
                args = processor.provideIoArgs();
            }

            try {
                if (args == null) {
                    processor.onConsumeFailed(null, new IOException("ProvideIoArgs is null."));
                } else {
                    int count = args.writeTo(channel);
                    if (count == 0) {
                        System.out.println("Current write zero data!");
                    }
                    if (args.remained()) {
                        //附加当前未消费的Args
                        attach = args;
                        //再次注册数据发送
                        ioProvider.registerOutput(channel, this);
                    } else {
                        attach = null;
                        processor.onConsumeCompleted(args);
                    }

                }
            }catch (IOException ignored){
                CloseUtils.close(SocketChannelAdapter.this);
            }
        }


    };




    //如果channel发生异常 还要做一个回调 告诉上层
    public interface onChannelStatusChangedListener{
        void onChannelClosed(SocketChannel channel);
    }
}
